Skip to content

fix: correct Sony ARW2 de-interleave and tone-curve expansion#21

Merged
ethanrous merged 5 commits into
mainfrom
fix/sony-arw2-interleave-tonecurve
Jun 7, 2026
Merged

fix: correct Sony ARW2 de-interleave and tone-curve expansion#21
ethanrous merged 5 commits into
mainfrom
fix/sony-arw2-interleave-tonecurve

Conversation

@ethanrous

Copy link
Copy Markdown
Owner

Summary

Sony A7 IV (ILCE-7M4) compressed .ARW files (the ARW2 / lossy cRAW codec) rendered with vertical comb striping and ~8× too dark. The ARW2 decode path had never been exercised by a real file — both committed Sony fixtures (sony.ARW, sony2.ARW) are ILCE-7SM3 uncompressed and take the Uncompressed14 path — so two bugs shipped:

  • No column de-interleave. sony_arw2_load_raw wrote each 16-pixel block to consecutive columns. ARW2 actually interleaves: a block fills every other column (stride 2), and consecutive blocks alternate even/odd phase across a 32-column span. This caused the vertical comb artifact. Ported LibRaw/dcraw's col += 2 … col -= col&1 ? 1 : 31 logic.
  • No tone-curve expansion. The 11-bit codes were stored raw with white_level = 0x3fff, leaving the image crushed and dark. They are now expanded through the Sony tone curve (curve[pix << 1]), built from the SonyToneCurve EXIF tag (0x7010), into the ~14-bit linear domain; white_level is 0x3ff0.

Changes:

  • Add build_sony_tone_curve (port of the dcraw/LibRaw curve construction).
  • Rewrite sony_arw2_load_raw (de-interleave + curve + white_level 0x3ff0, new tone_curve: &[u16] param); restore the malformed-block row-buffer overread guard.
  • Wire load_sony_raw to read the tone-curve tag from EXIF and pass the built curve.

The Uncompressed14 path and all other decoders are untouched.

Test plan

  • cargo test -p agno --no-default-features --features jpeg,png --lib — 217 unit tests pass, including new arw2_deinterleaves_columns_and_applies_tone_curve and build_sony_tone_curve_* tests
  • Real A7 IV ARW2 files render clean (no stripes, correct exposure/color) — verified on two files
  • Uncompressed fixtures (sony.ARW, sony2.ARW) still decode correctly — no regression

Note: an integration test against a real ARW2 file is intentionally not committed (the only available samples are personal 35 MB photos); coverage is via synthetic unit tests plus the manual visual verification above.

ethanrous added 4 commits June 6, 2026 23:07
Port of dcraw/LibRaw's sony_curve construction: reduces four u16 control
points with `>> 2 & 0xfff`, brackets with 0 and 4095, and fills each
segment incrementing by `1 << i`. Returns a 0x4000-entry Vec<u16> for
use as `curve[pixel << 1]` during ARW2 block decoding. Includes unit
test validating the A7 IV control points against expected dcraw output.
ARW2 (Sony cRAW, e.g. A7 IV/ILCE-7M4) decoded with a vertical comb
artifact and ~8x too dark because each 16-pixel block was written to
consecutive columns and the 11-bit codes were stored without the Sony
tone curve. Port LibRaw's sony_arw2_load_raw: write every other column
with alternating even/odd phase and expand through curve[pix << 1]
built from the SonyToneCurve tag; set white_level to 0x3ff0.
Malformed blocks where imax == imin cause 15 ordinary pixels to be
decoded (instead of 14), pushing `byte_index + 1` to `dp + 17 =
raw_width + 1` on the last block of a row. The previous version of
`sony_arw2_load_raw` rejected that with a clean error return; the
rewrite dropped the check. Restored it.

Also appended a comment documenting the tone_curve length invariant
(`>= 0x1000` entries; largest index is `0x7ff << 1` = 0xffe).
Copilot AI review requested due to automatic review settings June 7, 2026 03:37

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes decoding of Sony A7 IV (ILCE-7M4) compressed ARW2 files by correcting block de-interleaving (removing vertical comb striping) and applying Sony’s tone-curve expansion so the decoded pixel domain matches expected brightness/exposure.

Changes:

  • Add build_sony_tone_curve() to construct the ARW2 linearization table from EXIF SonyToneCurve (0x7010).
  • Rewrite sony_arw2_load_raw() to de-interleave columns correctly and expand 11-bit codes via the tone curve; update ARW2 white_level.
  • Update Sony loader to read SonyToneCurve from EXIF and pass the derived curve into the ARW2 decoder.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.

File Description
agno/src/sony_decoder.rs Implements ARW2 tone curve building and correct de-interleaving + curve expansion during decode; adds unit tests.
agno/src/agno_image/load/sony.rs Wires EXIF SonyToneCurve extraction into the ARW2 compressed decode path.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread agno/src/sony_decoder.rs
Comment thread agno/src/sony_decoder.rs
Comment thread agno/src/sony_decoder.rs Outdated
Comment thread agno/src/sony_decoder.rs
@ethanrous ethanrous merged commit b49dd7d into main Jun 7, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants